﻿using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
using System.Text;
using Quizz.DataRepository.Models;
using System.Linq.Dynamic;

namespace Quizz.Service.Services
{
    public class QuestionService : QuizzDomainService<QuizzDataContext>
    {
        public Question GetById(long id)
        {
            var loadOption = new DataLoadOptions();
            loadOption.AssociateWith<Question>(q => q.Answers.OrderBy(a => a.OrderChar));
            loadOption.LoadWith<Question>(q => q.Subject);
            loadOption.LoadWith<Question>(q => q.Creator);
            loadOption.LoadWith<Question>(q => q.Answers);
            
            DataContext.LoadOptions = loadOption;

            var result =  DataContext.Questions.FirstOrDefault(q => q.Id == id);
            result.ChildQuestions.Load();
            return result;
        }

        public IEnumerable<Question> GetAllForUser(long userid, string orderColumns)
        {
            return CompiledQuestionService.GetAllForUser(DataContext, userid, orderColumns);
        }

        public IEnumerable<Question> GetAllForUserPage(long userId, int page, int count, string orderColumn)
        {
            return CompiledQuestionService.GetAllForUserPage(DataContext, userId, page, count, orderColumn);
        }

        public void Insert(Question question)
        {
            DataContext.Questions.InsertOnSubmit(question);
            DataContext.SubmitChanges();
        }


        public void Update(Question question)
        {
            var original = CompiledQuestionService.GetById(DataContext, question.Id);

            original.Content = question.Content;
            original.Sumary = question.Sumary;
            original.Note = question.Note;
            original.ShareType = question.ShareType;
            original.Level = question.Level;
            original.ParentQuestionId = question.ParentQuestionId;
            original.CreatorId = question.CreatorId;
            original.SubjectId = question.SubjectId;

            DataContext.Answers.DeleteAllOnSubmit(original.Answers);
            original.Answers.Clear();
            original.Answers.AddRange(question.Answers);

            this.DataContext.SubmitChanges();
        }

        public bool Delete(long id)
        {
            try
            {
                var sql = @"DELETE [Question] WHERE [Id] = {0}";
                ExecuteCommand(sql, id);
                return true;
            }
            catch
            {
                return false;
            }
        }

        public List<Question> GetQuestionPage(long userId, long subjectId, int page, int count, string orderCol, ref int sumCount)
        {
            var loadOptions = new DataLoadOptions();
            loadOptions.LoadWith<Question>(q => q.Subject);

            DataContext.LoadOptions = loadOptions;

            if (subjectId == -1)
            {
                var items = DataContext.Questions.Where(q => q.CreatorId == userId && q.ParentQuestionId == null && q.OriginalQuestionId == null).OrderBy(orderCol);
                sumCount = items.Count();
                return items.Skip(page * count).Take(count).ToList();
            }
            else
            {
                var items = DataContext.Questions.Where(a => a.CreatorId == userId && a.SubjectId == subjectId && a.OriginalQuestionId == null && a.ParentQuestionId == null);
                sumCount = items.Count();

                return items.Skip(page * count).Take(count).ToList();
            }
        }
    }

    internal static class CompiledQuestionService
    {
        public static Func<QuizzDataContext, long, Question> GetById =
            CompiledQuery.Compile<QuizzDataContext, long, Question>(
                (ctx, id) => ctx.Questions.FirstOrDefault(q => q.Id == id));

        public static Func<QuizzDataContext, long, string, IEnumerable<Question>> GetAllForUser =
            CompiledQuery.Compile<QuizzDataContext, long, string, IEnumerable<Question>>(
                (ctx, userId, orderColumn) => ctx.Questions.Where(q => q.CreatorId == userId).OrderBy(orderColumn));

        public static Func<QuizzDataContext, long, int, int, string, IEnumerable<Question>> GetAllForUserPage =
            CompiledQuery.Compile<QuizzDataContext, long, int, int, string, IEnumerable<Question>>(
                (ctx, userid, page, count, orderCols) =>
                ctx.Questions.Where(q => q.CreatorId == userid).OrderBy(orderCols).Skip(page*count).Take(count));

        public static Func<QuizzDataContext, long, int, string, IEnumerable<Question>> GetAllType =
            CompiledQuery.Compile<QuizzDataContext, long, int, string, IEnumerable<Question>>(
                (ctx, userid, type, orderCols) =>
                ctx.Questions.Where(q => q.CreatorId == userid && q.Type == type).OrderBy(orderCols));

        public static Func<QuizzDataContext, long, int, int, int, string, IEnumerable<Question>> GetByTypePage =
            CompiledQuery.Compile<QuizzDataContext, long, int, int, int, string, IEnumerable<Question>>(
                (ctx, userid, type, page, count, orderCols) =>
                ctx.Questions.Where(q => q.CreatorId == userid && q.Type == type).OrderBy(orderCols).Skip(page*count).Take
                    (count));

        public static Func<QuizzDataContext, long, int, string, IEnumerable<Question>> GetByLevel =
            CompiledQuery.Compile<QuizzDataContext, long, int, string, IEnumerable<Question>>(
                (ctx, userid, level, orderCols) =>
                ctx.Questions.Where(q => q.CreatorId == userid && q.Level == level).OrderBy(orderCols));

        public static Func<QuizzDataContext, long, int, int, int, string, IEnumerable<Question>> GetByLevelPage =
            CompiledQuery.Compile<QuizzDataContext, long, int, int, int, string, IEnumerable<Question>>(
                (ctx, userid, level, page, count, orderCols) =>
                ctx.Questions.Where(q => q.CreatorId == userid && q.Level == level).OrderBy(orderCols).Skip(page*count).
                    Take(count));
    }
}
